

  

  

<main class="main-container ng-scope" ng-view="">
<div class="main receptacle post-view ng-scope">

  <article class="entry ng-scope" ng-controller="EntryCtrl" ui-lightbox="">
    <header>
      <h1 class="entry-title ng-binding">Ruby on Rails 动态渲染远程代码执行漏洞 (CVE-2016-0752)</h1>

      <div class="entry-meta">
        <a target="_blank" class="author name ng-binding">
          小饼仔</a>
        <span class="bull">·</span>
        <time title="2016/01/27 17:03" ui-time="" datetime="2016/01/27 17:03" class="published ng-binding ng-isolate-scope">2016/01/27 17:03</time>
      </div>
    </header>

    <!-- ngIf: isCensoring -->

    <section class="entry-content ng-binding" ng-bind-html="postContentTrustedHtml">
      <p>
        </p><p>原文：<a href="https://nvisium.com/blog/2016/01/26/rails-dynamic-render-to-rce-cve-2016-0752/">Rails Dynamic Render to RCE (CVE-2016-0752)</a></p>

<h1>0x00 概述</h1>

<hr>

<p>如果你的应用中使用了动态渲染路径 ( <code>dynamic render paths</code> ) ，如渲染<code>params[:id]</code>，通过本地文件包含（<code>local file inclusion</code>），可能会导致远程代码执行。可以通过更新到Rails的最新版本，或重构你的controllers来修复漏洞。</p>

<p>文章主要介绍了在特定的场景下，<code>Ruby on Rails</code> 框架的一个缺陷导致攻击者能够远程执行代码。</p>

<p>在 <code>Rails controllers</code> 的设计中，会根据被调用的方法，隐式的渲染对应的 <code>view</code> 文件。例如，当调用 <code>controller</code> 的 <code>show</code> 方法时，如果代码中没有明确指定要渲染的 <code>view file</code>，框架就会隐式的渲染 <code>show.html.erb</code> 文件。</p>

<p>然而在很多情况下，开发者会根据请求格式，如 <code>text, JSON, XML</code> 来明确渲染的内容。此时， <code>view file</code> 是一个模板语言文件，如 <code>ERB, HAML</code> 等。<code>Rails</code> 框架中有多个方法能够用于影响和改变 <code>view</code> 内容。本文中重点关注渲染方法（<code>render method</code>）。<code>Rails</code> 的文档中给出了多种调用渲染方法的方式，包括使用 <code>file:</code> 选项来明确指定要渲染的 <code>view file</code> 路径。</p>

<!--more-->

<p>如果你阅读了该方法的<a href="http://guides.rubyonrails.org/layouts_and_rendering.html">文档</a>，你会对功能的说明感到迷惑。让我们来看一段代码：</p>

<pre><code>def show
  render params[:template]
end
</code></pre>

<p>第一眼看，这段代码非常简单，该 <code>controller action</code> 的主要功能为渲染 <code>template</code> 参数指定 view 模板。但Rails如何查找指定的模板呢？在 <code>views</code> 目录下查找？ 在应用的 root 目录下查找？或是在其他位置？；该参数的值是一个模板的名称？是一个有特定后缀的文件名？或是一个完整的文件路径？这里有许许多多的疑问，我们需要查看实现的细节才能够得到答案。</p>

<h1>0x01 细节说明</h1>

<hr>

<p>框架的渲染机制（<code>render mechanism</code>）是一个在单一函数内试图完成太多功能的例子，这也是导致远程代码执行的原因所在。</p>

<p>我们假定渲染机制的预期行为是渲染在 <code>app/views/user/#{params[:template]}</code> 文件，该假设看起来似乎是合理的。如果 <code>template</code> 参数的值为 <code>dashboard</code>，那么就会去加载 <code>app/views/user/dashboard.{ext}</code> 文件，其中 <code>.ext</code> 是任意允许的后缀类型，如 <code>.html, .haml, .html.erb</code> 等</p>

<p><img alt="图片" img-src="b7ace96ed0382ef22f2f0bacf11c757ed7b5da3c.jpg"></p>

<p>假设用户给出的 <code>template</code> 参数值为 <code>../admin/dashboard</code>。 程序执行的结果会是什么？ 如下图所示，执行后，程序抛出了缺少模板错误（<code>missing template error</code>）</p>

<p><img alt="图片" img-src="b4766d367e27f95c3df74afff8757a84cec4f8a3.jpg"></p>

<p>通过分析报错信息，我们可以知道，框架试图在多个路径下查找要渲染的 <code>view file</code>，包括 <code>RAILS_ROOT/app/views</code>，<code>RAILS_ROOT</code> 和 文件系统的根目录。</p>

<p>从文件系统的根目录加载并渲染文件的行为是非常危险的。如果我们将 <code>/etc/passwd</code> 作为 <code>template</code> 参数的值传入，并且能够读取到 <code>passwd</code> 文件的内容。那么将会是一个很严重的问题。</p>

<p><img alt="图片" img-src="7e7e891b8ebd34aefac02b0247e93b39213c7dd6.jpg"></p>

<p>如果我们能够读取 <code>passwd</code> 文件的内容，那么也可以读取应用程序的源代码和配置文件，如 <code>config/initializers/secrettoken.rb</code> 文件。</p>

<p><img alt="图片" img-src="30503417f88adfbf56fcca070f3e9725557a1b4b.jpg"></p>

<p>导致该问题的原因是，在应用中使用了动态渲染路径（<code>dynamic render paths</code>）</p>

<pre><code>def show
  render params[:template]
end
</code></pre>

<p>这个简单的代码的例子证明了攻击者能够读取我们的源代码和应用程序配置文件。不幸的是，这不是最坏的结果。</p>

<p>如 <code>Jeff Jarmo</code> 在他的文章 <a href="http://matasano.com/research/AnatomyOfRailsVuln-CVE-2014-0130.pdf">The Anatomy of a Rails Vulnerability – CVE-2014-0130: From Directory Traversal to Shell</a> 中描述的，我们能够利用这个漏洞获得一个shell。<code>Jeff</code> 的文章中描述了 在某些版本的Rails的 隐式渲染机制的一个相似漏洞，能够允许目录遍历（<code>directory traversal</code>），更精确的说，本地文件包含（<code>local file inclusion</code>）。本文中重点关注显示渲染（<code>explicit rendering</code>），这是一个由框架开发者所引入的漏洞。</p>

<p>在进入细节分析前，这里将该漏洞的分类归为文件包含而不是目录遍历，原因是我们将文件作为代码（<code>ERB</code>）进行加载、解释并执行。从传统意义上来说，目录遍历漏洞返回的是不可执行的（<code>non-executable</code>）的内容，如 <code>CSV</code> 文件。因此从本质来说，我们不仅仅能够读取应用程序的源代码和其他可读的系统文件，还能够执行 <code>Ruby</code> 代码。既然我们能够执行 <code>Ruby</code> 代码，我们也能够在 <code>web server</code> 上执行系统级别（<code>system-level</code>）的命令。</p>

<p>在从文件包含到得到 <code>shell</code> 的过程中，用到了一种关键的技术，称为 日志文件污染 (<code>log file tainting</code>)。<code>Rails</code> 在运行过程中，会将请求信息记录到日志文件中，包括请求参数，如 <code>development.log</code> 。日志文件是纯文本格式，能够包含 <code>Ruby</code> 代码。日志文件污染可以通过向 <code>web</code> 应用程序发送一个恶意的请求，请求的参数中包含有效的 <code>Ruby</code> 代码来实现。</p>

<p>在下面的例子中，我们向<code>web</code> 应用程序发起了一个合法的请求，但在 <code>URL</code> 中带上了包含恶意的、经过 <code>URL</code> 编码的参数 <%= \`ls\`="" %="">。</%=></p>

<p><img alt="图片" img-src="ccc399c82d2fe9f124cf5157468059e3c4d60145.jpg"></p>

<p>通过查看日志文件，我们可以看到，日志中请求参数是以 <code>hash</code> 键值对的方式保存，并进行了 URL解码。这是有效的 <code>Ruby</code> 代码，能够在文件被渲染时执行。</p>

<p><img alt="图片" img-src="31fe9b426887072f6b9d6368ebdd6bdb353492cc.jpg"></p>

<p>因此，我们能够利用文件包含漏洞来尝试加载日志文件，执行包含的 <code>Ruby</code> 代码。</p>

<p><img alt="图片" img-src="5a261f0768e051853a436555f369b52c5c303ff7.jpg"></p>

<p>当日志文件返回时，我们能够看到参数的 <code>hash</code> 值。之前包含我们 <code>payload</code> 的部分已经被 <code>ls</code> 命令的执行结果所替换。到这里，我们已经能够以 <code>web-server</code> 对应用户权限来执行系统命令了。</p>

<h1>0x02 修复方法 &amp; 缓解措施</h1>

<hr>

<p>安装 <code>Rails</code> 特定版本的 <a href="https://groups.google.com/forum/#!topic/rubyonrails-security/335P1DcLG00">补丁</a></p>

<p>如果还没有安装 <code>patch</code>，可以考虑禁止渲染白名单之外的文件。具体方法为，在 <code>action</code> 中定义允许的文件名白名单 <code>hash</code>，对用户的参数进行校验，确保参数在文件白名单 <code>hash</code> 中。这种方法需要在应用程序中所有使用到动态渲染路径的地方都增加校验。</p>

<pre><code>def show
  template = params[:id]

  valid_templates = {
    "dashboard" =&gt; "dashboard",
    "profile"   =&gt; "profile",
    "deals"   =&gt; "deals"
  }

  if valid_templates.include?(template)
    render " #{valid_templates[template]}"
  else
    # throw exception or 404
  end
end
</code></pre>

<p>另一种类似的方法为校验给定的文件是否在特定的目录下存在。</p>

<pre><code>def show
  template = params[:id]
  d = Dir["myfolder/*.erb"]

  if d.include?("myfolder/#{template}.erb")
    render "myfolder/#{template}"
  else
    # throw exception or 404
  end
end
</code></pre>

<p>此外，我们可以使用 <code>Rails</code> 静态分析工具 <a href="http://brakemanscanner.org/">Brakeman</a>来扫描应用程序。<code>Brakeman</code> 检测报告会给出使用了动态渲染路径的 <code>controllers</code>，可以根据此来分析哪些 <code>controllers</code> 会有远程代码执行的风险。</p>

<h1>0x03 时间轴</h1>

<hr>

<ul>
<li>2015年2月1日漏洞被报告给 <code>Rails Team</code></li>
<li>2015年2月10日 <code>Rails Team</code> 同意修复漏洞</li>
<li><code>Patch</code> 在2015年7月内部验证通过。-- 距离报告日期超过5个月</li>
<li><code>Patch</code> 在2016年1月25日发布，漏洞编号 <a href="https://groups.google.com/forum/#!topic/rubyonrails-security/335P1DcLG00">CVE-2016-0752</a>，-- 距离验证通过超过6个月，距离报告日期将近一年</li>
</ul>

<h1>0x04 结论</h1>

<hr>

<p><code>Rails</code> 的渲染机制是一个比较神秘的功能，如果没有深入挖掘实现细节很难弄明白。与 <code>CVE-2014-0130</code>类似，使用动态渲染路径会导致目录遍历和代码执行。在评估多个流行的 <code>Rails</code> 开源项目的过程中，我已经看过许多由框架开发者所引入的类似漏洞。</p>

<p>如果你还没有阅读过 <code>Jeff Jarmoc</code> 的文章，我建议你去阅读以下。他深入了研究了 <code>CVE-2014-0130</code> 的漏洞细节和风险点。本文中的许多内容与他的文章都很相似，事实上，这两个是非常相似的漏洞。</p>

<p>我已经写了 <code>Metasploit</code> 的 <a href="https://gist.github.com/forced-request/5158759a6418e6376afb">POC模块</a>，用于检测和攻击 <code>web</code> 应用程序的远程打码执行漏洞。</p>

<p><img alt="图片" img-src="2990b2c6af9a8e529ace7fd40c2bdca97aca4a12.jpg"></p>

<p>已经有白帽子在三个白帽上搭建起了相应的漏洞环境，小伙伴们感兴趣的来测试下吧，有效期一个小时：</p>

<p>http://b4bfc94e13431d5d4.jie.sangebaimao.com</p>      <p></p>
    </section>
  </article>
  <!-- collect -->
  <div class="entry-controls clearfix">
		<div style="float:left;color:#9d9e9f;font-size:15px">
			<span>
				&copy;乌云知识库版权所有 未经许可 禁止转载
			</span>
		</div>
        

      </div>

          <div id="donate" style="padding: 10px;border-top: 1px solid #d9d9d9;text-align: center;"><span>碎银子打赏，作者好攒钱娶媳妇：</span><br><br><img src="http://static.wooyun.org/wooyun/upload/donate/20160325101543245a92728e13f23a463b7f3e1131a466.jpeg" style="width:200px; height:200px"></div>
  <!-- collect end -->
  <!-- recommend -->
  <div class="yarpp-related">
<h3>为您推荐了适合您的技术文章:</h3>
<ol id="recommandsystem">
		<li><a href="http://drops.wooyun.org/web/12750" rel="bookmark" id="re1">Rails Security (上)</a></li>
			<li><a href="http://drops.wooyun.org/papers/61" rel="bookmark" id="re2">分析下难得一见的ROR的RCE（CVE－2013－0156）</a></li>
			<li><a href="http://drops.wooyun.org/papers/653" rel="bookmark" id="re3">搭建基于Suricata+Barnyard2+Base的IDS前端Snorby</a></li>
			<li><a href="http://drops.wooyun.org/papers/1419" rel="bookmark" id="re4">弱随机化种子漏洞科普</a></li>
	 
</ol>
</div>
  <!-- recommend end -->
  <!-- comment -->
  <div id="comments" class="comment-list clearfix">
            
          <div id="comment-list">
    
    <div class="note-comment">
      <img class="avatar" alt="30" src="http://wooyun.b0.upaiyun.com/wooyun_job/avatar/default.png">
      <div class="content">
        <div class="comment-header">
          <span class="author-link">vforbox</span>
                 <span class="reply-time">2016-04-06 14:11:18</span>
        </div>
        <p></p><p>mark</p>
<p></p>
        
      </div>
    </div>
    
    <div class="note-comment">
      <img class="avatar" alt="30" src="http://wooyun.b0.upaiyun.com/wooyun_job/avatar/default.png">
      <div class="content">
        <div class="comment-header">
          <span class="author-link">_Evil</span>
                 <span class="reply-time">2016-01-28 09:14:38</span>
        </div>
        <p></p><p>http://www.lijiejie.com/python-django-directory-traversal/ 好像</p>
<p></p>
        
      </div>
    </div>
    
    <div class="note-comment">
      <img class="avatar" alt="30" src="http://wooyun.b0.upaiyun.com/wooyun_job/avatar/default.png">
      <div class="content">
        <div class="comment-header">
          <span class="author-link">BeenQuiver</span>
                 <span class="reply-time">2016-01-27 21:10:24</span>
        </div>
        <p></p><p>666</p>
<p></p>
        
      </div>
    </div>
    
    <div class="note-comment">
      <img class="avatar" alt="30" src="http://wooyun.b0.upaiyun.com/wooyun_job/avatar/default.png">
      <div class="content">
        <div class="comment-header">
          <span class="author-link">fdsfds</span>
                 <span class="reply-time">2016-01-27 18:13:42</span>
        </div>
        <p></p><p>fsdfds</p>
<p></p>
        
      </div>
    </div>
      </div>
  </div>
  <!-- comment end -->
  
</div>
</main>